﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace HostDetector
{
    public class Deobfuscator
    {
        
        byte[,] grid = new byte[256, 256];
        Dictionary<IPEndPoint, int[]> connections = new Dictionary<IPEndPoint, int[]>();
        List<byte[]> keys = new List<byte[]>();

        private enum Flip
        {
            f2 = 2,
            f8 = 8,
            f16 = 16,
            f32 = 32,
            f64 = 64,
            f128 = 128,
            f256 = 256
        }
        public Deobfuscator()
        {
            
            generateGrid();
            keys.Add(Encoding.ASCII.GetBytes("memberjo"));
            keys.Add(Encoding.ASCII.GetBytes("tystate\0"));
            keys.Add(Encoding.ASCII.GetBytes("ectRespo"));
            keys.Add(Encoding.ASCII.GetBytes("entInfo\0"));
            keys.Add(Encoding.ASCII.GetBytes("joinlobb"));
            keys.Add(Encoding.ASCII.GetBytes("hallenge"));
            keys.Add(Encoding.ASCII.GetBytes("memberco"));
            keys.Add(Encoding.ASCII.GetBytes("lengeRes"));
            
                
                
        }
        int[] generateLookUpTable(byte[] data, byte[] key)
        {
            int[] columns = new int[8];

            for (int i = 0; i < 8; i++)
            {

                for (int col = 0; col < 256; col++)
                {
                    
                    if (grid[col, key[i]] == data[24 + i])
                    {
                        columns[i] = col;
                        break;
                    }
                }
            }
            return columns;
        }
        bool testTable(byte[] data, int[] columns)
        {
            return grid[columns[0], data[16]] == 255 && grid[columns[1], data[17]] == 255 && grid[columns[2], data[18]] == 255 && grid[columns[3], data[19]] == 255;
        }
        public bool decodePacket(byte[] data, IPEndPoint ip)
        {
            int[] columns = null;
            if (connections.ContainsKey(ip))
            {
                columns = connections[ip];
            }

            if (columns == null || !testTable(data, columns))
            {

                bool columnsFound = false;
                foreach (byte[] key in keys)
                {
                    columns = generateLookUpTable(data, key);
                    if (testTable(data, columns))
                    {
                        columnsFound = true;
                        Console.WriteLine("Found key using: " + ASCIIEncoding.ASCII.GetString(key) + ", "+ ip);
                        break;
                    }
                }

                if (columnsFound == false)
                    columns = null;
                else
                    connections[ip] = columns;
            }

            if (columns != null)
            {
                for (int i = 0; i < data.Length; i++)
                {
                    data[i] = grid[columns[i % 8],data[i]];
                }
            }
            return columns != null;
        }

        private void flipFlop(int c, Flip flip)
        {

            int pivot = (int)flip;
            int half = pivot / 2;// lol, this is the pivot
            int ROWS = 256;

            for (int r = 0; r < ROWS; r += pivot)
            {
                if ((r + pivot - 1) <= ROWS)
                {
                    for (int offset = 0; offset < half; offset++)
                    {
                        int top = offset + r;
                        byte temp = grid[c, top + half];
                        grid[c, top + half] = grid[c, top];
                        grid[c, top] = temp;
                    }
                }
            }
        }

        private void generateGrid()
        {


            for (int c = 0; c < 128; c++)
            {
                for (int r = 0; r < 256; r++)
                {
                    grid[c, r] = (byte)r;
                }
            }
            for (int c = 128; c < 256; c++)
            {
                for (int r = 255; r >= 0; r--)
                {
                    grid[c, 255 - r] = (byte)r;
                }
            }
            for (int i = 0; i < 128; i++)
            {
                if ((i & 1) > 0)
                {
                    flipFlop(i, Flip.f2);
                    flipFlop(i + 128, Flip.f2);
                }
                if ((i & 2) > 0)
                {
                    flipFlop(i, Flip.f8);
                    flipFlop(i + 128, Flip.f8);
                }
                if ((i & 4) > 0)
                {
                    flipFlop(i, Flip.f16);
                    flipFlop(i + 128, Flip.f16);
                }
                if ((i & 8) > 0)
                {
                    flipFlop(i, Flip.f32);
                    flipFlop(i + 128, Flip.f32);
                }
                if ((i & 16) > 0)
                {
                    flipFlop(i, Flip.f64);
                    flipFlop(i + 128, Flip.f64);
                }
                if ((i & 32) > 0)
                {
                    flipFlop(i, Flip.f128);
                    flipFlop(i + 128, Flip.f128);
                }
                if ((i & 64) > 0)
                {
                    flipFlop(i, Flip.f256);
                    flipFlop(i + 128, Flip.f256);
                }
            }
        }
    }
}
